package com.naiterui.ehp.bp.support.context;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;

/**
 * 基于ThreadLocal的资源持有器
 * 用于在当前上下文中绑定资源
 * 参照TransactionSynchronizationManager
 * @author zhouyanxin
 * @since 1.0.0
 */
public abstract class ResourceHolder {

    private static final Logger LOGGER = LoggerFactory.getLogger(ResourceHolder.class);

    private static ThreadLocal<Map<String, Object>> resourceHolder = new NamedThreadLocal<>("reqeust resource");

    public static void bindResource(String key, Object value) {
        Map<String, Object> map = resourceHolder.get();
        if (map == null) {
            map = new HashMap<>();
            resourceHolder.set(map);
        }
        Object oldValue = map.put(key, value);
        LOGGER.trace("Bound value {} for key {} to thread {} previous value {}", value, key, Thread.currentThread().getName(), oldValue);
    }

    public static boolean hasResource(String key) {
        Object value = doGetResource(key);
        return value != null;
    }

    public static Object getResource(String key) {
        Object value = doGetResource(key);
        LOGGER.trace("Retrieved value {} for key {} bound to thread {}", value, key, Thread.currentThread().getName());
        return value;
    }

    public static Object unbindResource(String key) {
        Map<String, Object> map = resourceHolder.get();
        if (map == null) {
            return null;
        }
        Object value = map.remove(key);
        if (map.isEmpty()) {
            resourceHolder.remove();
        }
        LOGGER.trace("Removed value {} for key {} from thread {}", value, key, Thread.currentThread().getName());
        return value;
    }

    public static void clear() {
        resourceHolder.remove();
        LOGGER.trace("remove all values to thread", Thread.currentThread().getName());
    }

    public static Map<String, Object> getResourceMap() {
        Map<String, Object> map = resourceHolder.get();
        return map != null ? Collections.unmodifiableMap(map) : new HashMap<>();
    }

    private static Object doGetResource(String key) {
        Map<String, Object> map = resourceHolder.get();
        if (map == null) {
            return null;
        }
        return map.get(key);
    }
}
